/*
Automatic clinic tests using a robot arm.
Copyright (C) 2010  CIC-CPC, CHU Gabriel Montpied
All other trademarks, logos and copyrights are the property
of their respective owners.

This file is part of cpc-painbot.

cpc-painbot is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

cpc-painbot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with cpc-painbot.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CPC_PAINBOT_RACK_H
#define CPC_PAINBOT_RACK_H

#include <QObject>
#include <QMap>

class Filament;
class PositionBras;
class QIODevice;

/*! Rack de Filaments.
    Un Rack est un conteneur de Filaments. Il est capable de les fournir suivant leurs
    caractéristiques (masse, diamètre), ou individuellement.
*/
class Rack : public QObject
{
Q_OBJECT
//! Nom du Rack.
Q_PROPERTY(QString nom READ nom WRITE setNom)
//! Description.
Q_PROPERTY(QString description READ description WRITE setDescription)
//! Hauteur du Rack.
Q_PROPERTY(qreal hauteur READ hauteur WRITE setHauteur)
//! Espacement des lamelles.
Q_PROPERTY(qreal espacement READ espacement WRITE setEspacement)
//! Position du premier élément.
Q_PROPERTY(PositionBras* position READ position WRITE setPosition)
public:
    //! Itérateur.
    typedef QMap<int, Filament*>::ConstIterator Iterateur;

    /*! \name Chargement/Enregistrement.
        Chargement/enregistrement depuis/vers un fichier XML.
    */
    //@{
    /*! Charge les données depuis un fichier XML.
        Charge les données depuis un fichier XML ayant la structure appropriée.

        \param[in] fichier Chemin du fichier à charger.
        \param     parent  Parent du Rack chargé.

        \retval 0     Le chargement n'a pas pu avoir lieu (fichier mal formatté...)
        \retval Rack* Un rack dont le parent est défini à parent.
    */
    static Rack *charger(QIODevice *fichier, QObject *parent = 0);

    /*! Enregistre un Rack.
        Enregistre le Rack dans un fichier XML.
        \param[in] rack    Rack à sauvegarder.
        \param[in] fichier Chemin du fichier dans lequel sauver les données.

        \retval true  La sauvegarde s'est effectuée correctement.
        \retval false Une erreur s'est produite.
    */
    static bool sauver(const Rack *rack, const QIODevice *fichier);
    //@}

    //! Constructeur.
    explicit Rack(QObject *parent = 0);

    /*! Nom du Rack.
        \return le nom de ce Rack.
    */
    QString nom() const { return nom_; }

    /*! Description du Rack.
        \return La description de ce rack.
    */
    QString description() const { return description_; }

    /*! Hauteur du Rack.
        \return La hauteur du Rack.
    */
    qreal hauteur() const { return hauteur_; }

    /*! Espacement des lamelles.
        \return l'espace entre deux outils.
    */
    qreal espacement() const { return espacement_; }

    /*! Position du premier élément.
        Position du premier élément.
        La position de tous les autres est calculée à partir de celle-ci.
        \return La position du premier élément.
    */
    PositionBras *position() const { return position_; }

    /*! Ajoute un Filament à une position donnée.
        \param[in] position Position du Filament.
        \param     filament Filament à ajouter.
    */
    void ajouter(int position, Filament *filament) { filaments_.insert(position, filament); }

    /*! Obtient le Filament à l'emplacement donné.
        \param[in] e Emplacement désiré.

        \retval 0         Si l'emplacement est vide ou n'existe pas.
        \retval Filament* Le Filament à cet emplacement.
    */
    Filament *filament(int e) { return filaments_.value(e, 0); }

    /*! Liste des emplacements.
        Liste des emplacements occupés.
        \return La liste des emplacements occupés.
    */
    QList<int> emplacements() const { return filaments_.keys(); }

    /*! Liste des filaments.
        Fournit la liste des Filament du Rack, triée suivant les clés.
        \return La liste des filaments sur le rack.
    */
    QList<Filament*> filaments() const { return filaments_.values(); }

    Iterateur iterateur() const { return filaments_.constBegin(); }
    Iterateur fin() const { return filaments_.constEnd(); }

signals:

public slots:
    /*! Change le nom.
        \param[in] nom Nouveau nom.
    */
    void setNom(const QString &nom) { nom_ = nom; }

    /*! Change la description.
        \param[in] description Nouvelle description.
    */
    void setDescription(const QString &description) { description_ = description; }

    /*! Change la hauteur.
        \param[in] hauteur Nouvelle hauteur.
    */
    void setHauteur(qreal hauteur) { hauteur_ = hauteur; }

    /*! Change l'espacement.
        \param[in] espacement Nouvel espacement.
    */
    void setEspacement(qreal espacement) { espacement_ = espacement; }

    /*! Change la position.
        \param[in] position Nouvelle position.
    */
    void setPosition(PositionBras *position) { position_ = position; }

protected:
    QString nom_; //!< Nom du rack.
    QString description_; //!< Description.
    qreal hauteur_; //!< Hauteur du Rack.
    qreal espacement_; //!< Espacement des lamelles.
    PositionBras *position_; //!< Position du premier élément.
    QMap<int, Filament*> filaments_; //!< Filaments du Rack.
};
#endif // CPC_PAINBOT_RACK_H
